package com.stone.design.mode.prototype;

import lombok.Data;

import java.util.ArrayList;
import java.util.Map;

/**
 * 邮件实体对象
 * 原型模式必须要实现Cloneable接口 + 覆写Object对象的clone方法，可以看到Cloneable是一个标识接口，啥方法也没有
 * 注意：原型模式的clone是浅拷贝，只能拷贝对象里的基本数据类型 + string类型，【引用类型】仍然是指向的同一个对象，
 * 如果要实现深拷贝，那么可以自己改造一下clone方法
 *
 * @author Mr_wenpan@163.com 2022/03/14 21:43
 */
@Data
public class Mail implements Cloneable {

    /**
     * 收件人(这里使用list这个引用类型，暂时clone浅拷贝的问题)
     */
    private ArrayList<String> receivers = new ArrayList<>();
    /**
     * 邮件主题名称
     */
    private String subject;
    /**
     * 称谓
     */
    private String appellation;
    /**
     * 邮件内容
     */
    private String context;
    /**
     * 邮件结尾
     */
    private String tail;
    private Map<String, String> map;

    /**
     * 构造函数（在我们规定的业务场景下，邮件是通过邮件模板进行填充的一些基本信息，所以需要使用这个构造函数）
     */
    public Mail(MailTemplate template) {
        // 真实情况下这里的构造情况会特别复杂（一般构造器很复杂的情况下建议采用原型模式，因为clone时不走构造方法，加速新对象的创建）
        subject = template.getSubject();
        appellation = template.getAppellation();
        tail = template.getTail();
    }

    /**
     * 原型模式必须覆写这个接口，因为在对象克隆时需要用到这个方法直接将【对象的二进制流进行拷贝】，不会调用构造方法进行创建对象
     */
    @Override
    protected Mail clone() throws CloneNotSupportedException {
        Mail result = (Mail) super.clone();
        // 引用对象无法进行深拷贝，所以需要在这里将本对象的引用类型拷贝一份
        result.receivers = (ArrayList<String>) receivers.clone();
        // 返回拷贝后的对象
        return result;
    }
}
